#ifndef CPERSUIT_H
#define CPERSUIT_H
/*
 * The C Performance Test Suite
 */
#include <time.h>
#include <stddef.h>

#define CPS_INTERFACE_VERSION 1

typedef enum Cps_Big_O Cps_Big_O;

enum Cps_Big_O
{
	CPS_O_UNKNOWN,
	CPS_O_CONST,
	CPS_O_LOG,
	CPS_O_LINEAR,
	CPS_O_NLOG,
	CPS_O_SQUARE,
	CPS_O_END
};

typedef struct Cps_Stopwatch Cps_Stopwatch;
struct Cps_Stopwatch
{
	struct timespec time;
	struct timespec start;
};

void cps_stopwatch_start(Cps_Stopwatch *watch);
void cps_stopwatch_stop(Cps_Stopwatch *watch);

/* 
 * Callback to perform the test
 *
 * @param run: The number of runs (the N in the big O notation)
 */
typedef void Cps_Run_Cb(unsigned int run, Cps_Stopwatch watches[]);

typedef struct Cps_Run Cps_Run;
/*
 * The type definition of the Run structure
 */
struct Cps_Run
{
	const char *name;
	Cps_Run_Cb *func;
	unsigned int start;
	unsigned int stop;
	unsigned int step;
	Cps_Big_O *os;
};

typedef struct Cps_Run_List Cps_Run_List;
struct Cps_Run_List
{
	unsigned int interface_version;
	Cps_Run *runs;
};


#define CPS_RUN(name, func, start, stop, step, ...) \
	{name, func, start, stop, step, \
	(Cps_Big_O[]){ __VA_ARGS__, CPS_O_END}}
#define CPS_RUN_LIST Cps_Run_List cps_run_list = \
			{ CPS_INTERFACE_VERSION, (Cps_Run[]) {
#define CPS_RUN_LIST_END , CPS_RUN(NULL, NULL, 0, 0, 0, CPS_O_UNKNOWN)}};

typedef struct Cps_Graph Cps_Graph;
struct Cps_Graph
{
	int run_number;
	int run_section;
};

typedef struct Cps_Plot Cps_Plot;
struct Cps_Plot
{
	const char *title;
	Cps_Graph *graphs;
};

typedef struct Cps_Plot_List Cps_Plot_List;
struct Cps_Plot_List
{
	int interface_version;
	Cps_Plot *plots;
};

#define CPS_GRAPH(num, sec) {num, sec}
#define CPS_PLOT(title, ...) \
	{title, (Cps_Graph[]){ __VA_ARGS__, {-1, -1}}}
#define CPS_PLOT_LIST Cps_Plot_List cps_plot_list = \
			{ CPS_INTERFACE_VERSION, (Cps_Plot[]) {
#define CPS_PLOT_LIST_END , CPS_PLOT(NULL, CPS_GRAPH(-1, -1))}};

#endif /* CPERSUIT_H */
